﻿using System;
using System.Diagnostics.Contracts;
using System.Globalization;
using EPiServer.PlugIn;
using OpenWaves.EPiServer.CustomProperties;

namespace OpenWaves.EPiServer.GeoProperties
{
    [PropertyDefinitionTypePlugIn(DisplayName = "GeoPoint Picker")]        
    public class PropertyGeoPoint : StringProperty<GeoPoint>
    {
        public const string UiHint = "ow.geopoint";
        public const string GeoPointViewUiHint = "ow.geopointview";
        public const string UniqueName = "propertyGeoPoint";

        public PropertyGeoPoint()
        {            
        }

        private PropertyGeoPoint(GeoPoint geoPoint)
        {
            this.Value = geoPoint;
        }

        protected override StringProperty<GeoPoint> CreateInstance(GeoPoint value)
        {
            return new PropertyGeoPoint(value);
        }

        protected override string SerializeValue(GeoPoint value)
        {
            return value.ToSerializedString();            
        }

        protected override GeoPoint DeserializeValue(string serializedValue)
        {
            return GeoPoint.Parse(serializedValue);
        }

        protected override GeoPoint DefaultValue
        {
            get { return null; }
        }
    }

    [Serializable]
    public class GeoPoint
    {
        public double Latitude { get; set; }

        public double Longitude { get; set; }

        public int MapZoom { get; set; }

        public GeoPoint()
        {

        }
        /// <summary>
        /// Initializes a new instance of the GeoPoint class with specified latitude and longitude.
        /// </summary>
        /// <param name="latitude">Latitude component of the position in range [-90, 90].</param>
        /// <param name="longitude">Longitude component of the position in range [-180, 180].</param>
        /// /// <param name="mapZoom">Map zoom in range[0, 21].</param>
        public GeoPoint(double latitude, double longitude, int mapZoom)
        {
            Contract.Requires(latitude >= -90 && latitude <= 90, "Precondition failed");
            Contract.Requires(longitude >= -180 && longitude <= 180, "Precondition failed");
            Contract.Requires(mapZoom >= 0 && mapZoom <= 21, "Precondition failed");

            this.Latitude = latitude;
            this.Longitude = longitude;
            this.MapZoom = mapZoom;
        }                

        /// <summary>
        /// Parses string representation of a <see cref="GeoPoint"/> into an instance of <see cref="GeoPoint" /> class.
        /// </summary>
        /// <param name="value">String representation of a <see cref="GeoPoint"/> formated as "latitude, longitude" where both components are floats (InvariantCulture).</param>
        /// <returns>New instance of <see cref="GeoPoint"/></returns>
        /// <exception cref="FormatException">value is a missformated string.</exception>
        public static GeoPoint Parse(string value)
        {
            Contract.Requires(value != null, "Precondition failed");

            string[] stringArray = value.Split(',');
            if (stringArray.Length != 3)
            {
                throw new FormatException("String should be in format \"lat,lng,zoom\"");
            }
            return new GeoPoint(double.Parse(stringArray[0], CultureInfo.InvariantCulture), double.Parse(stringArray[1], CultureInfo.InvariantCulture), int.Parse(stringArray[2], CultureInfo.InvariantCulture));
        }
    }

    public static class GeoPointExtensions
    {
        public static string GetImageUrl(this GeoPoint point, int width, int height, string apiKey = null)
        {
            return
                string.Format(
                    "//maps.googleapis.com/maps/api/staticmap?center={0},{1}&zoom={2}&size={3}x{4}&sensor=false&markers={0},{1}&key={5}",
                    point.Latitude.ToString(CultureInfo.InvariantCulture), point.Longitude.ToString(CultureInfo.InvariantCulture), point.MapZoom, width,
                    height, apiKey ?? ServiceLocator.Resolve<IGeoPropertyConfiguration>().GoogleMapsApiKey);

        }

        public static string ToSerializedString(this GeoPoint geoPoint)
        {
            return String.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", geoPoint.Latitude, geoPoint.Longitude, geoPoint.MapZoom);
        }
    }
}